package twitter.RequestParser;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.log4j.BasicConfigurator;

import org.apache.log4j.Logger;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

import twitter.TwitterLibrary.Utility;

/*********************************************************
 * this class is designed for writing the xml style request 
 * send to back end server from front end server
 * @author fang
 *
 */
public class XMLWriter {
	private HashMap<String, Document> versionCache = null;
	private HashMap<String, Integer> tagCache=null;
	private final ReentrantReadWriteLock rwl;
	
	private final Lock w ;
	private DocumentBuilderFactory factory = null;
	private Document DOC_query = null;
	private int maxversion = -1;
	static Logger logger=Logger.getLogger(XMLWriter.class);
	private Utility utility;

/******************************************************
 * Class constructor
 * @param factory:DocumentBuilderFactory
 * @param versionCache
 * @param tagCache
 * @param rwl: the read write lock
 */
	public XMLWriter(DocumentBuilderFactory factory,HashMap<String, Document> versionCache,HashMap<String, Integer> tagCache, ReentrantReadWriteLock rwl,Utility utility) {
		this.rwl=rwl;
		w=this.rwl.writeLock();
		this.factory = factory;
		this.versionCache=versionCache;
		this.tagCache=tagCache;
		this.utility=utility;
		BasicConfigurator.configure();
		
	}
	/************************
	 * return the max version
	 * @return
	 */
	public int getMaxVersion() {
		return this.maxversion;
	}
/******************************************************
 * write the get query for version by hash tag
 * <query httptype="GET" returntype="2" tag="TAG">
 * returntype=2,just return the version.
 * </query>
 */
	public String queryForVersion(String query) {
		DocumentBuilder db = null;
		try {
			db = factory.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		DOC_query = db.newDocument();
		Element DB_query = DOC_query.createElement("query");
		DB_query.setAttribute("tag", query);
		DB_query.setAttribute("returntype", "2");
		DB_query.setAttribute("httptype", "GET");
		DOC_query.appendChild(DB_query);
		return utility.xmlToString(DOC_query);

	}
	/********************************************************
	 * write the get query for status and version by hash tag
	 * <query httptype=\"GET\" returntype=\"1\" tag=\""+tag+"\"></query>
	 *  returntype=1 means return everything,status,version,and tag
	 * @param query
	 * @return
	 */
	
	public String queryForAll(String query)
	{
		DocumentBuilder db = null;
		try {
			db = factory.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		DOC_query = db.newDocument();

		Element DB_query = DOC_query.createElement("query");
		DB_query.setAttribute("tag", query);
		DB_query.setAttribute("returntype", "1");
		DB_query.setAttribute("httptype", "GET");
		DOC_query.appendChild(DB_query);
		return utility.xmlToString(DOC_query);
	}
	/***************************************
	 * write the post query for add the new status to the back end server
	 * <query httptype=\"POST\" status=\"newStatus\" ></query>
	 * @param newStatus
	 * @return
	 */
	
	public String postNewStatus(String newStatus)
	{
		DocumentBuilder db = null;
		try {
			db = factory.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		DOC_query = db.newDocument();

		Element DB_query = DOC_query.createElement("query");
		
		DB_query.setAttribute("httptype", "POST");
		DB_query.setAttribute("status", newStatus);
		DOC_query.appendChild(DB_query);
		return utility.xmlToString(DOC_query);
	}
	/******************************************************
	 * search the status for query
	 * @param tag
	 * @return
	 */
	
	public String queryForStatus(String tag)
	{
		DocumentBuilder db = null;
		try {
			db = factory.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		DOC_query = db.newDocument();

		Element DB_query = DOC_query.createElement("query");
		DB_query.setAttribute("tag", tag);
		DB_query.setAttribute("searchfor", "status");
		return utility.xmlToString(DOC_query);
	}
/********************************************************
 * write the front end post response send to the client
 * @param results
 * @return
 */
	public String writeTwitts(HashMap<String, ArrayList<String>> results) {
		DocumentBuilder db = null;
		try {
			db = factory.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Document DOC_tweets = db.newDocument();

		Element DB_tweets = DOC_tweets.createElement("tweets");

		ArrayList<String> querylist = results.get("tag");
		ArrayList<String> statuslist = results.get("status");
		ArrayList<String> versionlist = results.get("version");
		String query = (String) querylist.get(0);
		DB_tweets.setAttribute("query", query);
		DB_tweets.setAttribute("cached", "no");
		

		
		if (statuslist.size() > 0) {
			for (int i = 0; i < statuslist.size(); i++) {
				String status = (String) statuslist.get(i);
				int version = Integer.parseInt((String) versionlist.get(i));
				if (maxversion < version) {
					maxversion = version;

				}
				Element tweet = DOC_tweets.createElement("tweet");
				tweet.setTextContent(status);

				DB_tweets.appendChild(tweet);

			}
			DOC_tweets.appendChild(DB_tweets);
		

			w.lock();
			try {
				logger.info("writing into the front end server cache and the lock information is : "+rwl.toString());
				
				
				versionCache.put(query, DOC_tweets);
				tagCache.put(query, getMaxVersion());
			
				return utility.xmlToString(DOC_tweets);
			} finally {
				w.unlock();
			}
		
		} else {
			return "<tweets>no result</tweets>";
		}

	}
/************************************************
 * change the tag fron no cached to "yes"
 * @param DOC_tweets
 * @return
 */
	public String changeCached(Document DOC_tweets) {
		
		Node tweets = DOC_tweets.getFirstChild();
		NamedNodeMap atts = tweets.getAttributes();
		
			Node att = atts.getNamedItem("cached");
			att.setNodeValue("yes");
		
		System.out.println("retrive data from cache!!");
		System.out.println(utility.xmlToString(DOC_tweets));
		return utility.xmlToString(DOC_tweets);
	}
	

}
